from xml.sax.handler import ContentHandler
from xml.sax import make_parser

def parse_subs(stream, class_, **classargs):
	p = make_parser()
	h = class_(**classargs)
	p.setContentHandler(h)
	p.parse(stream)
	return (p, h)

class SubsBase:
	"""
	This class is equivalent to perl XML::Parser::Style::Subs. It is a base class for XmlSubs. See XmlSubs documentation.
	"""
	_depth = 0
	depth = 0
	_state = True # States: False - skip, None - Parse with user handlers, any other - parse normally

	def _start_main(self, name, attrs):
		self.depth += 1
		if(self._state == None):
			self._start_current(name, attrs) # Run user-defined handler
			self._depth += 1
		elif(self._state == False):
			pass # Do nothing
		else:
			if(hasattr(self, 'start_'+name)):
				res = getattr(self, 'start_'+name)(attrs)
				if(res == False):
					self._state = None
					(self._start_current, self._end_current) = (self.empty, self.empty)
				elif(type(res) == tuple):
					self._state = None
					self._depth = 1
					(self._start_current, self._end_current) = res
				else: 
					self._state = True
				self._set_handlers(self._start_main, self._end_main)

		return True

	def _end_main(self, name):
		if(self._state == None):
			self._depth -= 1
			if(self._depth == 0):
				self._state = True # Tag end
			else:
				self._end_current(name) # Run user-defined handler
		else:
			if(hasattr(self, 'end_'+name)):
				res = getattr(self, 'end_'+name)()
				self._set_handlers(self._start_main, self._end_main)

		self.depth -= 1
		return True
	
	def _set_handlers(self, start, end):
		raise NotImplementedError, "Handlers must be set in derived classes"

	def empty(self, name='', attrs=None):
		return True

	_start_current = empty
	_end_current = empty

class XmlSubs(ContentHandler, SubsBase):
	"""
	This class is equivalent to perl XML::Parser::Style::Subs. 
	To use it derive your own class from this.
	This class should contain specially named functions that are to be run when the tag start or end is met by parser.
	Functions should have parameters similar to SAX handlers.
	Example:
	class C(SubsBase):
		def start_foo(self, attrs):
			print "foo started"
		
		def end_foo(self):
			print "foo ended"

	starting function (start_foo in example below) can return a value to change parser behaviour:
		- False - skip the contents of the tag met
		- a tuple of new SAX(!) handlers - all content inside tag will be processed with theese handlers, but only until the end of tag.
		- any other value - usual behaviour
	There's also specials, children can use:
		- empty - function doing nothing
		- self.depth - member counts tag depth. It can be useful sometimes
	"""
	def _set_handlers(self, start, end):
		self.startElement, self.endElement = start, end
	
	startElement = SubsBase._start_main
	endElement = SubsBase._end_main
